Q & A

Theming

bslib

As we mentioned earlier, the bslib package provides a modern UI toolkit for Shiny, R Markdown, and Quarto based on Bootstrap. It provides,

  • Custom theming of Shiny apps and R Markdown documents

  • Switch between different versions of Bootstrap

  • Modern UI components like cards, value boxes, sidebars, and more.

We will now take a look at the first two of these features.

Bootswatch

Due to the ubiquity of Bootstrap a large amount of community effort has gone into developing custom themes - a large free collection of these are available at bootswatch.com/.

bs_theme()

Provides a high level interface to adjusting the theme for an entire Shiny app,

  • Change bootstrap version via version argument

  • Pick a bootswatch theme via bootswatch argument

  • Adjust basic color palette (bg, fg, primary, secondary, etc.)

  • Adjust fonts (base_font, code_font, heading_font, font_scale)

  • and more

The object returned by bs_theme() can be passed to the theme argument of fluidPage() and similar page UI elements.

thematic

Simplified theming of ggplot2, lattice, and {base} R graphics. In addition to providing a centralized approach to styling R graphics, thematic also enables automatic styling of R plots in Shiny, R Markdown, and RStudio.

In the case of our flexdashboard (or other shiny app), all we need to do is to include a call to thematic_shiny() before the app is loaded.

  • Using the value "auto" will attempt to resolve the bg, fg, accent, or font values at plot time.

Demo 11 - Dynamic theming

demos/demo11.R

library(tidyverse)
library(shiny)
library(bslib)

d = readr::read_csv(here::here("data/weather.csv"))

d_vars = c("Average temp" = "temp_avg",
           "Min temp" = "temp_min",
           "Max temp" = "temp_max",
           "Total precip" = "precip",
           "Snow depth" = "snow",
           "Wind direction" = "wind_direction",
           "Wind speed" = "wind_speed",
           "Air pressure" = "air_press")

thematic::thematic_shiny(bg = "auto", fg = "auto", font = "auto")

ui = page_sidebar(
  theme = bs_theme(version = 5),
  title = "Weather Data",
  sidebar = sidebar(
    selectInput(
      "region", "Select a region", 
      choices = c("West", "Midwest", "Northeast", "South")
    ),
    selectInput(
      "name", "Select an airport", choices = c()
    )
  ),
  card(
    card_header(
      textOutput("title"),
      popover(
        bsicons::bs_icon("gear", title = "Settings"),
        selectInput(
          "var", "Select a variable",
          choices = d_vars, selected = "tavg"
        )
      ),
      class = "d-flex justify-content-between align-items-center"
    ),
    card_body(
      plotOutput("plot")
    ),
    full_screen = TRUE
  ),
  uiOutput("valueboxes")
)

server = function(input, output, session) {
  bslib::bs_themer()
  
  observe({
    updateSelectInput(
      session, "name",
      choices = d |>
        distinct(region, name) |>
        filter(region == input$region) |>
        pull(name)
    )
  })
  
  output$valueboxes = renderUI({
    clean = function(x) {
      round(x,1) |> paste("°C")
    }
    
    layout_columns(
      value_box(
        title = "Average Temp",
        value = mean(d_city()$temp_avg, na.rm=TRUE) |> clean(),
        showcase = bsicons::bs_icon("thermometer-half"),
        theme = "green"
      ),
      value_box(
        title = "Minimum Temp",
        value = min(d_city()$temp_min, na.rm=TRUE) |> clean(),
        showcase = bsicons::bs_icon("thermometer-snow"),
        theme = "blue"
      ),
      value_box(
        title = "Maximum Temp",
        value = max(d_city()$temp_max, na.rm=TRUE) |> clean(),
        showcase = bsicons::bs_icon("thermometer-sun"),
        theme = "red"
      )
    )
  })
  
  output$title = renderText({
    names(d_vars)[d_vars==input$var]
  })
  
  d_city = reactive({
    req(input$name)
    d |>
      filter(name %in% input$name)
  })
  
  output$plot = renderPlot({
    d_city() |>
      ggplot(aes(x=date, y=.data[[input$var]])) +
      geom_line()
  })
}

shinyApp(ui = ui, server = server)

Your turn - Exercise 06

Using code provided in exercises/ex06.R (which is the same as Demo 9’s) experiment with bslib’s themer tool to explore different themes .

  • Try changing the main theme as well as the foreground and background colors

  • Try changing one or more of the accent colors

  • Try the fonts being used (e.g. Prompt, roboto, Oswald, Fira Sans) and changing the base font size

10:00

Deploying Shiny apps

Your turn - Exercise 07

Go to shinyapps.io and sign up for an account if you don’t have one already.

  • You can create a new account via email & a password

  • or via o-auth through Google or GitHub.

If asked to pick a plan, use the Free option (more than sufficient for our needs here)

03:00

Organizing your app

For deployment generally apps will be organized as a single folder that contains all the necessary components (R script, data files, other static content).

  • Pay attention to the nature of any paths used in your code

    • Absolute paths are almost certainly going to break

    • Relative paths should be to the root of the app folder

  • Static files (e.g. css, js, etc.) generally are placed in the www/ subfolder

  • Your script does not need to be named app.R or ui.R/server.R

  • Check / think about package dependencies

Your turn - Exercise 08

Now we will publish our app to shinyapps.io (you will need to have completed Exercise 7)

  1. Package up ex08.R as an app in exercises/ex08app (you will need to create this folder)

    • Make sure to copy the data (weather.csv) into this folder
    • Adjust any paths if necessary
  2. Open the script file in exercises/ex08app and click the Publish Document button in the upper right of the pane (look for the icon)

    • You should be presented with the “Publish to server”, click on the Add New Account link in the upper right

    • Select shinyapps.io and follow the instructions to connect

    • When retrieving your token for shinyapps.ip you may need to click Dashboard first and then your name (both in the upper right)

Your turn - Exercise 08 (cont.)

  1. Once authenticated you should be back at the “Publish to server” dialog, use this to select which files to include (select your script and data file)

  2. Your Shiny app should now be deploying and should open on shinyapps.io once live - check to see if everything works, if not go back and check Steps 1 and 3.

10:00

Demo 12 - shinylive

One of the really exciting developments in the last couple of years is the ability to run R (and Python) inside a web browser using webasm. shinylive is a package that lets you bundle your shiny app as a static website that can be hosted any number of places.

We can build the site using,

shinylive::export("demos/demo12","demos/demo12/site")

you can then run a local server with just,

httpuv::runStaticServer("demos/demo12/site")

Other publishing options

  • For other R users - you can share your script(s) and data directly

    • or better yet, bundle them into an R package
  • Run a local instance of shiny server

  • Use shinyapps.io (public) or posit.cloud (within team)

  • Use Posit Connect

What next / what else

Mastering Shiny

Shiny user showcase

The Shiny User Showcase is comprised of contributions from the Shiny app developer community. The apps are categorized into application areas and presented with a brief description, tags, and for many, the source code. Note that many of these apps are winners and honorable mentions of our annual Shiny contest!

Shiny contest winners blog posts:

shinyjs

Easily improve the user experience of your Shiny apps in seconds

  • Hide (or show) an element

  • Disable (or enable) an input

  • Reset an input back to its original value

  • Delay code execution

  • Easily call your own JavaScript functions from R

DT

The R package DT provides an R interface to the JavaScript library DataTables. R data objects (matrices or data frames) can be displayed as tables on HTML pages, and DataTables provides filtering, pagination, sorting, and many other features in the tables.

  • Interactive tables

  • Tables as inputs

  • Editable tables

reactable

Interactive data tables for R, based on the React Table library and made with reactR.

  • Sorting, filtering, pagination
  • Grouping and aggregation
  • Built-in column formatting
  • Custom rendering via R or JavaScript
  • Expandable rows and nested tables
  • Conditional styling

htmlwidgets

The htmlwidgets package provides a framework for easily creating R bindings to JavaScript libraries. Widgets created using the framework can be:

  • Used at the R console for data analysis just like conventional R plots (via RStudio Viewer).
  • Seamlessly embedded within R Markdown documents and Shiny web applications.
  • Saved as standalone web pages for ad-hoc sharing via email, Dropbox, etc.

pool

The goal of the pool package is to abstract away the logic of connection management and the performance cost of fetching a new connection from a remote database. These concerns are especially prominent in interactive contexts, like Shiny apps (which connect to a remote database) or even at the R console.

See articles available at shiny.rstudio.com/articles/#data

Awesome Shiny Extensions

A curated list of awesome R packages that offer extended UI or server components for the R web framework Shiny.

Shiny Developer Series

The goals of the Shiny Developer Series are to showcase the innovative applications and packages in the ever-growing Shiny ecosystem, as well as the brilliant developers behind them! The series is composed of these components:

  • Interviews with guests …

  • Video tutorials and live streams …

Q&A

Workshop Survey





Thank you!

posit-conf-2024.github.io/shiny-r-intro/
posit-conf-2024/shiny-r-intro/
rundel@gmail.com
colin.rundel@duke.edu
rundel